/*
 * Copyright (c) 2010 Nokia Corporation.
 */

#include "symbianpicloader.h"
#include "PictureLoaderThread.h"

#include <exifread.h>
#include <f32file.h>
#include <eikdef.h>
#include <eikenv.h>
#include <e32std.h>
#include <e32base.h>
#include <ImageConversion.h>

SymbianPicLoader::SymbianPicLoader(MSymbianPicLoader* observer) :
    CActive(EPriorityUserInput)
{
    m_observer = observer;
    m_thumbnail = 0;
    m_exif = 0;
    m_imageDecoder = 0;
    m_Fs.Connect();
    CActiveScheduler::Add(this);
}

SymbianPicLoader::~SymbianPicLoader()
{
    Cancel();

    m_Fs.Close();

    if (m_thumbnail)
        delete m_thumbnail;
    if (m_exif)
        delete m_exif;

    if (m_imageDecoder)
        delete m_imageDecoder;
}

void SymbianPicLoader::loadImage(PictureData* data)
{
    // http://wiki.forum.nokia.com/index.php/CS000968_-_Using_Exif_API

    m_pictureData = data;
    m_pictureData->path.replace(QString("/"), QString("\\"));

    // QString to QBuf conversion
    TBuf<128> filename(m_pictureData->path.utf16());

    // Read picture data to memory
    RFile file;
    User::LeaveIfError(file.Open(CEikonEnv::Static()->FsSession(), filename, EFileRead));
    CleanupClosePushL(file);
    TInt size = 0;
    file.Size(size);

    // We do not read whole image to memory, because we parse only thumbnail from the exif
    if (size>50000) {
        size = 50000;
    }
    
    m_exif = HBufC8::NewL(size);
    TPtr8 bufferDes(m_exif->Des());
    User::LeaveIfError(file.Read(bufferDes,size));
    CleanupStack::PopAndDestroy(); // file

    // Create exif reader
    TInt err = KErrNone;
    TRAPD(exfErr,
        // Parse exif data from the "broken" jpeg picture, because we read only 50.000 bytes from
        // begining of the picture (CExifRead::ENoJpeg)
        CExifRead* read = CExifRead::NewL(m_exif->Des(),CExifRead::ENoJpeg);
        CleanupStack::PushL(read);
        
        // Read thumbnail data from exif 
        m_thumbnail = read->GetThumbnailL();
        
        // Clean memory
        CleanupStack::PopAndDestroy(read);
    );
    
    if (m_thumbnail && err==KErrNone && exfErr==KErrNone) {
        // Create CFbsBitmap from HBufC8 exif data
        convertImage();
    }
    else {
        // Exif data not found, send empty pixmap
        QPixmap p;
        m_observer->thumbLoaded(p, m_pictureData);
    }
}

void SymbianPicLoader::convertImage()
{
    // Create CFbsBitmap from HBufC8 exif data
    if (m_thumbnail && m_exif) {
        delete m_imageDecoder;
        m_imageDecoder = 0;

        delete m_cfbsBitmap;
        m_cfbsBitmap = 0;

        // Create the decoder
        m_imageDecoder = CImageDecoder::DataNewL(m_Fs, *m_thumbnail);

        // Create the destination bitmap
        m_cfbsBitmap = new (ELeave) CFbsBitmap();
        m_cfbsBitmap->Create(m_imageDecoder->FrameInfo().iOverallSizeInPixels,
            m_imageDecoder->FrameInfo().iFrameDisplayMode);

        // Start asynchronous operation
        m_imageDecoder->Convert(&iStatus, *m_cfbsBitmap);
        SetActive();
    }
}

void SymbianPicLoader::DoCancel()
{
    if (m_imageDecoder)
        m_imageDecoder->Cancel();
}

void SymbianPicLoader::RunL()
{
    if (iStatus == KErrNone) {
        // CFbsBitmap to QPixmap
        QPixmap pixmap = QPixmap::fromSymbianCFbsBitmap(m_cfbsBitmap);
        // Emit result
        m_observer->thumbLoaded(pixmap, m_pictureData);
    }
}

TInt SymbianPicLoader::RunError(TInt)
{
    return KErrNone;
}

